/**
 * - 作者: DoooReyn
 * - 日期: 2023.10.29
 * - 名称: Arrays
 * - 描述: 数组辅助工具
 */
export class Arrays {
    /**
     * 转换为字符串
     * @returns
     */
    static asString(list: any[]) {
        return list.length > 0 ? list.map((v) => v.toString()).join(',') : '';
    }

    /**
     * Fisher-Yates 随机置乱算法
     * @param list 目标数组
     */
    static shuffleInFisherYates(list: any[]): any[] {
        let count = list.length;
        let index = -1,
            temp: any;
        while (count) {
            index = Math.floor(Math.random() * count--);
            temp = list[count];
            list[count] = list[index];
            list[index] = temp;
        }
        return list;
    }

    /**
     * 头部随机置乱算法
     * @param list 目标数组
     */
    static shuffleInHead(list: any[]): any[] {
        let count = list.length;
        let index = -1,
            temp: any;
        for (let i = 0; i < count; i++) {
            index = Math.floor(Math.random() * count);
            temp = list[index];
            list[index] = list[0];
            list[0] = temp;
        }
        return list;
    }

    /**
     * 乱序随机置乱算法
     * @param list 目标数组
     */
    static shuffleInSorter(list: any[]) {
        return list.sort(() => Math.random() - 0.5);
    }

    /**
     * 按递增或递减排序
     * @param list 数字数组
     * @param ascending 递增或递减
     * @returns
     */
    static sortByOrder(list: number[], ascending: boolean = true) {
        return list.sort((a, b) => (ascending ? a - b : b - a));
    }

    /**
     * 数组去重
     * @param list 原始数组
     * @returns
     */
    static unique(list: any[]) {
        return list.filter((item, index, arr) => {
            return arr.indexOf(item, 0) === index;
        });
    }

    /**
     * 获得指定范围内的数值数组
     * @param start 起始数值
     * @param ended 终止数值
     * @param step 增进步幅
     * @returns
     */
    static range(start: number, ended: number, step: number = 1) {
        start = start | 0;
        ended = ended | 0;
        step = step | 0;
        let ret = [];
        if (step > 0) {
            [start, ended] = ended > start ? [start, ended] : [ended, start];
            for (let i = start; i <= ended; i += step) {
                ret.push(i);
            }
        } else if (step === 0) {
            ret.push(start, ended);
        } else {
            [start, ended] = ended > start ? [start, ended] : [ended, start];
            for (let i = ended; i >= start; i += step) {
                ret.push(i);
            }
        }
        return ret;
    }

    /**
     * 累加
     * @param list 数值数组
     * @returns
     */
    static sumOf(list: number[]) {
        return list.reduce((a, b) => a + b, 0);
    }

    /**
     * 乘积
     * @param list 数值数组
     * @returns
     */
    static productOf(list: number[]) {
        return list.reduce((a, b) => a * b, 1);
    }

    /**
     * 前进一步
     * @param list 数组
     */
    static forward(list: any[]) {
        list.length > 1 && list.unshift(list.pop());
    }

    /**
     * 后退一步
     * @param list 数组
     */
    static backward(list: any[]) {
        list.length > 1 && list.push(list.shift());
    }

    /**
     * 前进/后退 n 步
     * @param list 数组
     * @param step 步数
     */
    static advance(list: any[], step: number) {
        step = step | 0;
        if (step !== 0 && list.length > 1) {
            if (step > 0) {
                list.unshift(...list.splice(list.length - step, step));
            } else {
                for (let i = 0; i < -step; i++) {
                    list.push(list.shift());
                }
            }
        }
        return list;
    }

    /**
     * 数组合并与对齐
     * @param arrays 数组列表
     * @returns
     */
    static zip(...arrays: any[]): any[] {
        return Array.apply(null, new Array(arrays[0].length)).map((_: any, i: number) => {
            return arrays.map((array) => array[i]);
        });
    }

    /**
     * 数组扁平化
     * @param array 目标数组
     */
    static flatten(array: any[]) {
        while (array.some((v) => Array.isArray(v))) {
            array = [].concat.apply([], array);
        }
        return array;
    }

    /**
     * 合并数组
     * @param array1 目标数组1
     * @param array2 目标数组2
     */
    static combine(array1: any[], array2: any[]): any[] {
        return [...array1, ...array2];
    }

    /**
     * 截取第一个到指定个数的数组
     * @param list 数组
     * @param count 个数
     */
    static pickFromHead(list: any[], count: number) {
        return list.slice(0, count | 0);
    }

    /**
     * 截取从最后一个到指定个数的数组
     * @param list 数组
     * @param count 个数
     */
    static pickToTail(list: any[], count: number) {
        return list.slice((list.length - count) | 0, list.length);
    }

    /**
     * 随机获取数组索引
     * @param array 目标数组
     */
    static pickIndexFrom(array: any[]): number {
        if (array.length > 0) return (Math.random() * array.length) | 0;
        return -1;
    }

    /**
     * 随机获取数组成员
     * @param array 目标数组
     */
    static pickOneFrom(array: any[]): any {
        const size = array.length;
        if (size === 0) return undefined;
        else if (size === 1) return array[0];
        return array[this.pickIndexFrom(array)];
    }

    /**
     * 随机获取数组成员
     * @param array 目标数组
     */
    static pickManyFrom(array: any[], count: number): any[] {
        count = Math.min(array.length, Math.max(1, count | 0));
        return this.shuffleInFisherYates(array.slice()).slice(0, count);
    }

    /**
     * 是否包含指定项目
     * @param array 数组
     * @param item 指定项目
     */
    static contains<T>(array: T[], item: T) {
        return array.indexOf(item) > -1;
    }

    /** 
     * 使用数组扩充目标数组到指定长度
     * @param array 数组
     * @param length 目标数组长度长度
     * @param value 默认填充值
     */
    static fill(array: any[], length: number, value: any) {
        return Array.from({ length }, (_, i) => array[i] ?? value);
    }
}
